Define river network scheme
!! Define river network scheme !|author: <a href="mailto:giovanni.ravazzani@polimi.it">Giovanni Ravazzani</a> ! license: <a href="http://www.gnu.org/licenses/">GPL</a> ! !### History ! ! current version 1.2 - 22nd April 2024 ! ! | version | date | comment | ! |----------|-------------|----------| ! | 1.0 | 10/Feb/2023 | Original code | ! | 1.1 | 18/Apr/2024 | ChannelInitiation modified for following DischargeRouting update | ! | 1.2 | 22/Apr/2024 | Flow direction convention imported from Morphology | ! !### License ! license: GNU GPL <http://www.gnu.org/licenses/> ! !### Module Description ! routines to define river network scheme for discharge routing ! The original algorithms were initially implemented in a ! standalone program used to prepare input file to FEST. ! Starting from 2023 FEST release, river network ! topology orgamìnization is computed within the FEST ! before starting the simulation from the flow direction ! and flow accumulation maps. ! MODULE RiverDrainage !Modules used: USE GridLib, ONLY: & !Imported type definitions: grid_real, & grid_integer, & !Imported routines: NewGrid, & GridDestroy USE GridOperations, ONLY: & !Imported routines: IsOutOfGrid, & GetIJ, & GetXY, & CellArea USE DataTypeSizes, ONLY: & !Imported definitions: short, & float, & long USE LogLib, ONLY : & ! Imported Routines: Catch USE StringManipulation, ONLY: & !Imported routines: ToString USE Morphology, ONLY: & !Imported routines: HortonOrders , & CheckOutlet, & DownstreamCell, & DeriveSlope, & CellIsSpring USE GeoLib, ONLY: & !Imported definitions: Coordinate, & !Imported routines: Distance , & !Imported assignment: ASSIGNMENT (=) USE Utilities, ONLY: & !imported routines: GetUnit USE Morphology, ONLY : & !Imported variables: NW, & !North-West N, & !North NE, & !North-East W, & !West E, & !East SW, & !South-West S, & !South SE !South-East IMPLICIT NONE ! Local declarations: ! Local routines: PRIVATE :: SplitNetwork PRIVATE :: ExportReaches PRIVATE :: ExportShape TYPE Reach INTEGER :: id !==================================================== REAL(KIND = float) :: x0 !! beginning of reach x coordinate REAL(KIND = float) :: y0 !! beginning of reach y coordinate REAL(KIND = float) :: x1 !! end of reach x coordinate REAL(KIND = float) :: y1 !! end of reach y coordinate !==================================================== INTEGER :: i0 !! beginning of reach row INTEGER :: j0 !! beginning of reach column INTEGER :: i1 !! end of reach row INTEGER :: j1 !! end of reach column !==================================================== INTEGER :: ncells !!number of cells in a reach INTEGER :: order !! Horton-Sthraler order REAL(KIND = float) :: slope !! average reach slope (m/m) REAL(KIND = float) :: length !!reach length (m) REAL(KIND = float) :: area !! area drained by end section (m2) END TYPE Reach TYPE ReachNetwork TYPE(Reach),POINTER :: branch (:) INTEGER :: nreach END TYPE ReachNetwork TYPE ReachesList INTEGER :: id INTEGER :: i0 INTEGER :: j0 INTEGER :: i1 INTEGER :: j1 REAL (KIND = FLOAT) :: y0 REAL (KIND = FLOAT) :: x0 REAL (KIND = FLOAT) :: y1 REAL (KIND = FLOAT) :: x1 INTEGER :: n_cells REAL (KIND = FLOAT) :: slope ! (L/L) REAL (KIND = FLOAT) :: length !(m) REAL (KIND = FLOAT) :: area ! (cells) INTEGER :: order !Horton-Strhaler order TYPE (ReachesList), POINTER :: next !dynamic list END TYPE ReachesList !Global routines: PUBLIC :: BuildReachNetwork PUBLIC :: ChannelInitiation !private TYPE (ReachesList), POINTER, PRIVATE :: list, current, previous !======= CONTAINS !======= ! Define procedures contained in this module. !============================================================================== ! Description: ! Define cells where channels begin. The routine searches for channel cells ! that have no other input channel cells. !SUBROUTINE MarkChannelBeginning ! !local declaration: !INTEGER :: i,j !INTEGER :: row, col !LOGICAL :: inputFound ! !-----------------------end of declaration------------------------------------- ! !DO i = 1, channelBeginning % idim ! DO j = 1, channelBeginning % jdim ! IF (channel % mat (i,j) /= channel % nodata) THEN ! inputFound = .FALSE. ! ! !check EAST cell ! row = i ! col = j + 1 ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == W .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check SOUTH-EAST cell ! row = i + 1 ! col = j + 1 ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == NW .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check SOUTH cell ! row = i + 1 ! col = j ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == N .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check SOUTH-WEST cell ! row = i + 1 ! col = j - 1 ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == NE .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check WEST cell ! row = i ! col = j - 1 ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == E .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check NORTH-EAST cell ! row = i - 1 ! col = j - 1 ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == SE .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check NORTH cell ! row = i - 1 ! col = j ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == S .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! !check NORTH-EAST cell ! row = i - 1 ! col = j + 1 ! IF ( .NOT. IsOutOfGrid(row,col,channelBeginning) ) THEN ! IF (flowDirection % mat (row,col) == SW .AND. & ! channel % mat (row,col) /= channel % nodata ) THEN ! inputFound = .TRUE. ! channelBeginning % mat (i,j) = channelBeginning % nodata ! CYCLE ! END IF ! END IF ! ! IF ( .NOT. inputFound ) THEN ! channelBeginning % mat (i,j) = 1 ! END IF ! ! ELSE ! channelBeginning % mat (i,j) = channelBeginning % nodata ! END IF ! ! ! END DO !END DO ! ! !END SUBROUTINE MarkChannelBeginning !============================================================================== !| Description: ! Split channel network where a confluence of two different horton order ! channels occurs SUBROUTINE SplitNetwork & ! (orders, flowDirection, split) IMPLICIT NONE !Arguments with intent in: TYPE(grid_integer), INTENT(in) :: orders TYPE(grid_integer), INTENT(in) :: flowDirection !Arguments with intent out TYPE(grid_integer),INTENT(inout):: split !local declaration: INTEGER :: i,j INTEGER :: row, col INTEGER :: hortonOrder LOGICAL :: splitFound !-----------------------end of declaration------------------------------------- DO i = 1, split % idim DO j = 1, split % jdim !IF (channel % mat (i,j) /= channel % nodata) THEN hortonOrder = orders % mat (i,j) splitFound = .FALSE. !check EAST cell row = i col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == W .AND. & !channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check SOUTH-EAST cell row = i + 1 col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == NW .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder ) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check SOUTH cell row = i + 1 col = j IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == N .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder ) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check SOUTH-WEST cell row = i + 1 col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == NE .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder ) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check WEST cell row = i col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == E .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check NORTH-EAST cell row = i - 1 col = j - 1 IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == SE .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check NORTH cell row = i - 1 col = j IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == S .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder ) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF !check NORTH-EAST cell row = i - 1 col = j + 1 IF ( .NOT. IsOutOfGrid(row,col,split) ) THEN IF (flowDirection % mat (row,col) == SW .AND. & ! channel % mat (row,col) /= channel % nodata .AND. & orders % mat (row,col) < hortonOrder) THEN splitFound = .TRUE. split % mat (i,j) = 1 CYCLE END IF END IF IF ( .NOT. splitFound ) THEN split % mat (i,j) = split % nodata END IF !ELSE ! split % mat (i,j) = split % nodata !END IF END DO END DO END SUBROUTINE SplitNetwork !============================================================================== !| Description: ! Define channel cells. Two methods are possible: ! ! 1. area: channel begins where drainage basin exceedes a given area ! 2. ask: channel begins where AS<sup>k</sup> exceedes a given value, where A is ! the basin area (m<sup>2</sup>), S is the local slope (-), and k is the ! basin fractal dimension (default = 1.7) SUBROUTINE ChannelInitiation & ! (method, threshold, mask, flowAcc, flowDir, dem, channel ) IMPLICIT NONE !arguments with intent in: CHARACTER (LEN = *), INTENT(IN) :: method REAL (KIND = float), INTENT(IN) :: threshold TYPE (grid_integer), INTENT(IN) :: mask TYPE (grid_integer), INTENT(IN) :: flowAcc TYPE (grid_integer), INTENT(IN) :: flowDir TYPE (grid_real), INTENT(IN) :: dem !arguments with intent(inout): TYPE (grid_integer), INTENT(INOUT) :: channel !local declarations: INTEGER :: i,j,iu,ju,id,jd REAL :: area !! ( m<sup>2</sup> ) REAL :: scale = 1.7 REAL :: ask !!local value of AS<sup>k</sup> TYPE (grid_real) :: slope !----------------------end of declarations------------------------------------- !initialize channel to zero DO i = 1, dem % idim DO j = 1, dem % jdim IF (mask % mat (i,j) /= mask % nodata ) THEN channel % mat (i,j) = 0 END IF END DO END DO SELECT CASE (method) CASE ('area') DO i = 1, mask % idim DO j = 1, mask % jdim IF (mask % mat (i,j) /= mask % nodata ) THEN area = flowAcc % mat (i,j) * CellArea (flowAcc, i, j) IF (area >= threshold) THEN channel % mat (i,j) = 1 ELSE channel % mat (i,j) = 0 END IF END IF END DO END DO CASE ('ask') !compute slope in radians CALL DeriveSlope (dem, slope) DO i = 1, mask % idim DO j = 1, mask % jdim IF (mask % mat (i,j) /= mask % nodata ) THEN area = flowAcc % mat (i,j) * CellArea (flowAcc, i, j) ask = area * TAN (slope % mat (i,j)) ** scale IF (ask >= threshold) THEN !channel initiation found !set channel on all downstream cell iu = i ju = j DO channel % mat (iu,ju) = 1 CALL DownstreamCell (iu,ju,flowDir % mat(iu,ju),id,jd) IF ( CheckOutlet (iu,ju,id,jd,flowDir) ) EXIT iu = id ju = jd END DO END IF END IF END DO END DO CALL GridDestroy (slope) !other methods to be implemented END SELECT RETURN END SUBROUTINE ChannelInitiation !============================================================================== !| Description: ! Build reaches that compose the river network SUBROUTINE BuildReachNetwork & ! (maxReachLength, slopeCorrection, flowDirection, flowAcc, dem, & fileExport, shpExport, streamNetwork ) IMPLICIT NONE !arguments with intent(in): REAL (KIND = float), INTENT (IN) :: maxReachLength !!max length of a reach (m) REAL (KIND = float), INTENT (IN) :: slopeCorrection !! slope value to correct negative values TYPE (grid_integer), INTENT (IN) :: flowDirection !! flow direction TYPE (grid_integer), INTENT (IN) :: flowAcc !! flow accumulation TYPE (grid_real), INTENT (IN) :: dem !! digital elevation model INTEGER (KIND = short), INTENT (IN) :: fileExport, shpExport !arguments with intent (out): TYPE (ReachNetwork), INTENT (OUT) :: streamNetwork !local declarations LOGICAL :: outletSection LOGICAL :: endOfReach INTEGER :: countReaches INTEGER :: maxOrder INTEGER :: i,j,l !loop index INTEGER :: row,col !current cell INTEGER :: iDown, jDown !downstream cell INTEGER :: n_cells REAL :: reachLength TYPE (grid_integer) :: orderBeginning TYPE (grid_integer) :: orders TYPE (grid_integer) :: split TYPE (Coordinate) :: point1, point2 !- -----------------------------end of declarations---------------------------- !------------------------------------------------------------------------------ !(1.0) Initialize orders, orderBeginning and split grids !------------------------------------------------------------------------------ CALL NewGrid (orders, flowDirection) CALL NewGrid (orderBeginning, flowDirection) CALL NewGrid (split, flowDirection) !------------------------------------------------------------------------------ !(2.0) Build Horton orders grid !------------------------------------------------------------------------------ CALL HortonOrders (flowDirection, orders, maxOrder) !------------------------------------------------------------------------------ !(3.0) Build orderBeginning and split network !------------------------------------------------------------------------------ CALL MarkOrderBeginning (orders, flowDirection, orderBeginning) !split network CALL SplitNetwork (orders, flowDirection, split) !------------------------------------------------------------------------------ !(4.0) Build reaches !------------------------------------------------------------------------------ countReaches = 0 NULLIFY(list) ! at the beginning list is empty !initialize points to compute reach length point1 % system = flowDirection % grid_mapping point2 % system = flowDirection % grid_mapping DO l =1, maxOrder CALL Catch ('info', 'RiverDrainage', 'Elaborating reaches of stream order: ', & argument = ToString(l)) DO j=1,orderBeginning%jdim ! scan orderBeginning grid DO i=1,orderBeginning%idim IF(orderBeginning%mat(i,j) == l) THEN countReaches = countReaches + 1 reachLength = 0. n_cells = 0 row = i col = j endOfReach = .FALSE. outletSection = .FALSE. IF(.NOT.ASSOCIATED(list)) THEN ALLOCATE(list) !set first reach current => list ELSE ALLOCATE(current%next) !allocate next reach NULLIFY(current % next % next) current => current%next ENDIF current % i0 = i current % j0 = j current % order = l current % id = countReaches !follow the reach until an order change or to the outlet, !if it is the maximum order DO WHILE (.NOT. endOfReach) CALL DownstreamCell (row,col,flowDirection%mat(row,col), & iDown,jDown) n_cells = n_cells + 1 CALL GetXY (row, col, flowDirection, point1 % easting, point1 % northing) CALL GetXY (iDown, jDown, flowDirection, point2 % easting, point2 % northing) reachLength = reachLength + Distance (point1, point2) !length (m) IF ( CheckOutlet (row,col,iDown,jDown,flowDirection) ) THEN outletSection = .TRUE. endOfReach = .TRUE. ENDIF IF ( outletSection ) THEN current % i1 = row current % j1 = col current % n_cells = n_cells ! unit: cells (integer) current % length = reachLength ! !length (m) current % area = flowAcc % mat(row,col) ! * & !flowAccumulation % cellsize**2 ! if the reach length exceedes the maximum length => ! break the reach ELSEIF (maxReachLength > 0. .AND. & !if maximum length = 0 I do not break the reach reachLength >= maxReachLength ) THEN current % i1 = row current % j1 = col current % n_cells = n_cells current % length = reachLength !current % routingMethod = default current % area = flowAcc % mat(row,col) ! * & !flowAccumulation % cellsize**2 !(m2) !set elements for the following reach ALLOCATE(current % next) NULLIFY(current % next % next) current => current % next current % i0 = row current % j0 = col current % order = l countReaches = countReaches + 1 reachLength = 0. n_cells = 0 current % id = countReaches END IF IF ( .NOT. IsOutOfGrid(iDown,jDown,orders)) THEN IF (orders%mat(iDown,jDown) > l) THEN endOfReach = .TRUE. current % i1 = iDown current % j1 = jDown IF (n_cells == 0) THEN !this case occurs when a reach has just been terminated because too long current % n_cells = 1 CALL GetXY (row, col, flowDirection, point1 % easting, point1 % northing) CALL GetXY (iDown, jDown, flowDirection, point2 % easting, point2 % northing) current % length = Distance (point1, point2) ELSE current % n_cells = n_cells current % length = reachLength END IF current % area = flowAcc % mat(row,col) ! * & !flowAccumulation % cellsize**2 END IF END IF row = iDown col = jDown END DO ENDIF ENDDO ENDDO ENDDO !set other parameters !scan all list elements current => list DO !calculate slope from digital elevation model and check negative slope current % slope = ( dem % mat(current%i0,current%j0) - & dem % mat(current%i1,current%j1) ) / & current % length IF ( current % slope <= 0. ) THEN IF ( slopeCorrection > 0. ) current % slope = slopeCorrection ENDIF !calculate spatial coordinate CALL GetXY (current % i0, current % j0, dem, current % x0, current % y0) CALL GetXY (current % i1, current % j1, dem, current % x1, current % y1) IF ( .NOT. ASSOCIATED (current % next) )THEN !found last element of list EXIT END IF current => current % next END DO !------------------------------------------------------------------------------ !(5.0) remove temporary variables !------------------------------------------------------------------------------ CALL GridDestroy ( orders ) CALL GridDestroy ( orderBeginning ) !------------------------------------------------------------------------------ !(6.0) export files !------------------------------------------------------------------------------ IF ( fileExport > 0 ) THEN CALL ExportReaches ( ) END IF IF ( shpExport > 0 ) THEN CALL ExportShape ( dem, flowDirection ) END IF !------------------------------------------------------------------------------ !(7.0) populate stream network !------------------------------------------------------------------------------ ALLOCATE ( streamNetwork % branch (countReaches) ) streamNetwork % nreach = countReaches current => list DO i = 1, countReaches streamNetwork % branch (i) % id = current % id streamNetwork % branch (i) % i0 = current % i0 streamNetwork % branch (i) % j0 = current % j0 streamNetwork % branch (i) % i1 = current % i1 streamNetwork % branch (i) % j1 = current % j1 streamNetwork % branch (i) % x0 = current % x0 streamNetwork % branch (i) % y0 = current % y0 streamNetwork % branch (i) % x1 = current % x1 streamNetwork % branch (i) % y1 = current % y1 streamNetwork % branch (i) % ncells = current % n_cells streamNetwork % branch (i) % slope = current % slope streamNetwork % branch (i) % length = current % length streamNetwork % branch (i) % area = current % area streamNetwork % branch (i) % order = current % order current => current % next END DO RETURN END SUBROUTINE BuildReachNetwork !============================================================================== !| Description: ! Export reaches on file SUBROUTINE ExportReaches & ! ( ) IMPLICIT NONE !local declaration: INTEGER ( KIND = short ) :: fileunit !-----------------------end of declaration------------------------------------- fileunit = GetUnit () OPEN (unit = fileunit, file = 'stream_network.txt' ) WRITE (fileunit, '(a)') 'surface_routing_reaches' WRITE (fileunit, '(a)') ' ID X0 Y0 & X1 Y1 CELLS STHRALER_ORDER & SLOPE_L/L LENGTH_m DRAINED_CELLS ' !scan all list elements current => list DO WRITE(fileunit, '(I,3X,E,E,E,E,I,I,10x,E,1X,E,1X,E,I,11X,E,1X,E,& 1X,E,1X,E,1X,E,5X,E,E,E)') & current % id, current % x0, current % y0, & current % x1, current % y1, current % n_cells, & current % order, current % slope, current % length, & current % area IF ( .NOT. ASSOCIATED (current % next) ) THEN !found last element of list EXIT END IF current => current % next END DO CLOSE (fileunit) END SUBROUTINE ExportReaches !============================================================================== !| Description: ! Define cells where the beginning of a reach of different order takes place. SUBROUTINE MarkOrderBeginning & ! (orders, flowDirection, orderBeginning) IMPLICIT NONE !Arguments with intent in: TYPE(grid_integer),INTENT(in):: orders TYPE(grid_integer),INTENT(in):: flowDirection !Arguments with intent out TYPE(grid_integer),INTENT(inout):: orderBeginning LOGICAL :: outlet INTEGER :: row,col !current cell INTEGER :: iDown, jDown !downstream cell INTEGER :: reachOrder INTEGER :: maxPathOrder INTEGER :: i,j !- End of header -------------------------------------------------------------- DO j=1,orderBeginning%jdim DO i=1,orderBeginning%idim IF(CellIsSpring(i,j,flowDirection)) THEN !found a spring orderBeginning%mat(i,j) = 1 row = i col = j outlet = .FALSE. reachOrder = 1 DO WHILE (.NOT. outlet) ! follow the reach till the outlet CALL DownstreamCell(row,col,flowDirection%mat(row,col),iDown,jDown) outlet = CheckOutlet (row,col,iDown,jDown,flowDirection) IF (.NOT. outlet) THEN IF(orders%mat(iDown,jDown) == reachOrder + 1) THEN !found the beginning of a reach of increased order reachOrder = reachOrder + 1 orderBeginning%mat(iDown,jDown) = reachOrder ENDIF ENDIF row = iDown col = jDown END DO ENDIF ENDDO ENDDO !-----------remove duplicates------------ DO j=1,orderBeginning%jdim ! scan entire grid DO i=1,orderBeginning%idim IF(CellIsSpring(i,j,flowDirection)) THEN !found a spring row = i col = j outlet = .FALSE. maxPathOrder = 1 DO WHILE (.NOT. outlet) ! follow the reach till the outlet CALL DownstreamCell(row,col,flowDirection%mat(row,col),iDown,jDown) outlet = CheckOutlet (row,col,iDown,jDown,flowDirection) IF (.NOT. outlet) THEN IF(orderBeginning%mat(iDown,jDown) <= maxPathOrder) THEN !only one point where a N order reach begins is possible orderBeginning%mat(iDown,jDown) = 0 ELSEIF (orderBeginning%mat(iDown,jDown) > maxPathOrder) THEN maxPathOrder = orderBeginning%mat(iDown,jDown) ENDIF ENDIF row = iDown col = jDown END DO ENDIF ENDDO ENDDO RETURN END SUBROUTINE MarkOrderBeginning !============================================================================== !| Description: ! export shape file of river network SUBROUTINE ExportShape & ! ( dem, flowDirection ) IMPLICIT NONE !arguments with intent (in): TYPE (grid_real), INTENT (IN) :: dem TYPE (grid_integer), INTENT (IN) :: flowDirection !local declarations INTEGER :: K, jin,iin,ivalle,jvalle INTEGER :: dot REAL :: X,Y LOGICAL(4) :: res CHARACTER(300) :: command CHARACTER(300) :: filename INTEGER :: system !------------------------------------------------------------------------------ !------------------------------------------------------------------------------ !(1.1) create "generate file" !------------------------------------------------------------------------------ OPEN(unit=876,file='tratti.gen') OPEN(unit=877,file='tratti.csv') WRITE(877,'(a)')'#ID;X0;Y0;X1;Y1;CELLS;STHRALER;SLOPE_L/L;LENGTH_m;& DRAINED_CELLS' !scan all list elements current => list DO WRITE(876,*) current % id jin = current % j0 iin = current % i0 WRITE(877,'(I8,";",E14.7,";",E14.7,";",E14.7,";",E14.7,";",I8,";",I8,";",E14.7,";",& E14.7,";",E14.7,";",I8,";",E14.7,";",E14.7,";",E14.7,";",E14.7,";",E14.7)') & current % id, current % x0, current % y0, & current % x1, current % y1, current % n_cells, & current % order, current % slope, current % length, & current % area DO WHILE (.not.((jin.EQ.current%j1) .AND. & (iin.EQ.current%i1))) X = DEM%xllcorner + jin * DEM%cellsize - DEM%cellsize / 2. Y = DEM%yllcorner + (DEM%idim - (iin-1)) * DEM%cellsize - DEM%cellsize / 2. WRITE(876,'(f20.7,a1,f20.7)') X,',',Y CALL DownstreamCell(iin,jin,flowDirection%mat(iin,jin),ivalle,jvalle) iin = ivalle jin = jvalle END DO !end single reach X = DEM%xllcorner + jin * DEM%cellsize - DEM%cellsize / 2. Y = DEM%yllcorner + (DEM%idim - (iin-1)) * DEM%cellsize - DEM%cellsize / 2. WRITE(876,'(f20.7,a1,f20.7)') X,',',Y WRITE(876,'(a3)') 'end' IF ( .NOT. ASSOCIATED (current % next) )THEN !found last element of list EXIT END IF current => current % next END DO !end cycle on all reaches WRITE(876,'(a3)') 'end' CLOSE(876) CLOSE(877) !!------------------------------------------------------------------------------ !!(1.2) create shape file !!------------------------------------------------------------------------------ filename = 'stream_network' !dot = SCAN (filename,'.') !IF (dot /= 0) filename = filename(1:dot-1) command = 'gen2shp ' // filename(1:len_trim(filename)) // ' lines < tratti.gen' res = SYSTEM(command) !create dbf command='txt2dbf -C10 -R20.7 -R20.7 -R20.7 -R20.7 -I10 -I10 -R15.7 -R15.2 & -R15.2 -I10 -d ; tratti.csv ' // filename(1:len_trim(filename)) // '.dbf' res = SYSTEM(command) !------------------------------------------------------------------------------ !(1.3) delete intermediate files !------------------------------------------------------------------------------ res = SYSTEM('del tratti.gen') res = SYSTEM('del tratti.csv') RETURN END SUBROUTINE ExportShape END MODULE RiverDrainage